﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QValueAxis>
#include <QIODevice>
#include <stdio.h>
#include <QTimer>
#include <QDateTime>
#include <QElapsedTimer>
#include <QBarSet>
#include <QBarSeries>
#include <QGradient>

// MainWindow构造函数
// 参数: parent - 父窗口部件
// 功能: 初始化主窗口，设置UI，创建图表组件，配置音频设备等
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    // Setup UI - we'll manually handle connections later
    ui->setupUi(this);
    
    // The automatic connection warnings (penChanged, labelChanged, brushChanged) are harmless but annoying
    // They're likely coming from some Qt Charts internal components

    // 初始化计时器
    recordingTimer = new QTimer(this);
    connect(recordingTimer, &QTimer::timeout, this, &MainWindow::updateRecordingTime);
    recordingTimer->setInterval(1000); // 每秒更新一次

    // 初始化进度条
    ui->progressBar->setMinimum(0);
    ui->progressBar->setMaximum(3600); // 最大录音时长1小时
    ui->progressBar->setValue(0);
    ui->progressBar->setFormat("%v秒");

    // 初始化begin标签
    ui->begin->setText("准备录音");

    // 创建两个独立的图表
    lineChart = new QChart;
    lineChart->setTitle("音频输入原始信号 - 线性图");
    
    rectChart = new QChart;
    rectChart->setTitle("音频输入原始信号 - 矩形图");
    
    // 初始化线形图系列
    lineSeries = new QLineSeries();
    lineChart->addSeries(lineSeries);
    
    // 初始化条形图相关组件
    barSet = new QBarSet("音频级别");
    barSeries = new QBarSeries();
    barSeries->append(barSet);
    
    // 设置条形图样式为黄绿色渐变
    QLinearGradient gradient(QPointF(0, 0), QPointF(0, 1));
    gradient.setColorAt(0, Qt::green);
    gradient.setColorAt(1, Qt::yellow);
    gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
    barSet->setBrush(gradient);
    
    // 设置无边框
    barSet->setPen(Qt::NoPen);
    
    // 设置条形图中矩形项的宽度为相对值，使条形之间有适当间隔
    barSeries->setBarWidth(0.7); // 0.7表示占据类别宽度的70%，留有30%作为间隔
    
    rectChart->addSeries(barSeries);
    
    // 创建第二个图表视图
    rectChartView = new QChartView(rectChart);
    rectChartView->setRenderHint(QPainter::Antialiasing);
    ui->verticalLayout->addWidget(rectChartView);
    
    // 默认使用线形图
    currentChartType = LineChart;
    ui->chartView->setChart(lineChart);
    ui->chartView->show();
    rectChartView->hide(); // 初始隐藏矩形图

    // 初始化坐标轴 - 为线性图
    lineAxisX = new QValueAxis;
    lineAxisX->setRange(0, displayPointsCount);
    lineAxisX->setTitleText("Samples");
    
    lineAxisY = new QValueAxis;
    lineAxisY->setRange(0, 256);
    lineAxisY->setTitleText("Audio level");
    
    // 添加坐标轴到线性图表
    lineChart->addAxis(lineAxisX, Qt::AlignBottom);
    lineChart->addAxis(lineAxisY, Qt::AlignLeft);
    
    // 将坐标轴附加到线形图系列
    lineSeries->attachAxis(lineAxisX);
    lineSeries->attachAxis(lineAxisY);
    lineChart->legend()->hide();
    
    // 初始化坐标轴 - 为矩形图
    rectAxisX = new QValueAxis;
    rectAxisX->setRange(0, 10); // 固定显示10个条形
    rectAxisX->setTitleText("Frequency");
    
    rectAxisY = new QValueAxis;
    rectAxisY->setRange(0, 256);
    rectAxisY->setTitleText("Audio level");
    
    // 添加坐标轴到矩形图表
    rectChart->addAxis(rectAxisX, Qt::AlignBottom);
    rectChart->addAxis(rectAxisY, Qt::AlignLeft);
    
    // 将坐标轴附加到条形图系列
    barSeries->attachAxis(rectAxisX);
    barSeries->attachAxis(rectAxisY);
    rectChart->legend()->hide();

    // 初始化音频设备列表
    deviceList = QMediaDevices::audioInputs();
    for (const QAudioDevice &device : deviceList) {
        ui->comboDevices->addItem(device.description());
    }

    // 音频模式已经通过radio button设置，不再需要codec组合框

    // 采样率
    ui->comboSampleRate->addItems({"8000", "11025", "16000", "22050", "44100", "48000"});

    // 声道数
    ui->comboChannels->addItems({"1", "2"});

    // 采样格式
    ui->comboSampleTypes->addItem("UInt8", QAudioFormat::UInt8);
    ui->comboSampleTypes->addItem("Int16", QAudioFormat::Int16);
    ui->comboSampleTypes->addItem("Int32", QAudioFormat::Int32);
    ui->comboSampleTypes->addItem("Float", QAudioFormat::Float);

    // 采样大小（Qt6中与采样格式合并）
    ui->comboSampleSizes->addItems({"8", "16", "32"});

    // 字节序（使用QSysInfo）
    ui->comboByteOrder->addItem("Little Endian");
    ui->comboByteOrder->addItem("Big Endian");
    ui->comboByteOrder->setCurrentText(
        byteOrderToString(QSysInfo::ByteOrder));  // 默认使用系统字节序

    if (!deviceList.isEmpty()) {
        ui->comboDevices->setCurrentIndex(0);
        on_comboDevices_currentIndexChanged(0);  // 手动触发一次更新
    } else {
        ui->actStart->setEnabled(false);
        ui->actDeviceTest->setEnabled(false);
        ui->groupBoxDevice->setTitle("支持的音频输入设置(无设备)");
    }
}

// 采样格式转换为字符串
// 参数: format - 音频采样格式枚举值
// 返回值: 对应的可读字符串表示
// 功能: 将QAudioFormat::SampleFormat枚举转换为人类可读的字符串
QString MainWindow::sampleFormatToString(QAudioFormat::SampleFormat format)
{
    switch(format) {
    case QAudioFormat::UInt8: return "Unsigned 8-bit";
    case QAudioFormat::Int16: return "Signed 16-bit";
    case QAudioFormat::Int32: return "Signed 32-bit";
    case QAudioFormat::Float: return "Float";
    default: return "Unknown";
    }
}

// 字节序转换为字符串
// 参数: endian - 系统字节序枚举值
// 返回值: 对应的可读字符串表示
// 功能: 将QSysInfo::Endian枚举转换为人类可读的字符串
QString MainWindow::byteOrderToString(QSysInfo::Endian endian)
{
    return endian == QSysInfo::LittleEndian ? "Little Endian" : "Big Endian";
}

// 音频设备下拉框索引变化槽函数
// 参数: index - 选中的设备索引
// 功能: 当用户选择不同的音频输入设备时，更新当前设备设置和UI显示
void MainWindow::on_comboDevices_currentIndexChanged(int index)
{
    if(index < 0 || index >= deviceList.size()) return;

    curDevice = deviceList.at(index);
    format = curDevice.preferredFormat();

    // 更新UI显示当前设备支持的格式
    ui->comboSampleRate->setCurrentText(QString::number(format.sampleRate()));
    ui->comboChannels->setCurrentText(QString::number(format.channelCount()));

    // 设置采样格式
    int sampleTypeIndex = ui->comboSampleTypes->findData(format.sampleFormat());
    if(sampleTypeIndex >= 0) {
        ui->comboSampleTypes->setCurrentIndex(sampleTypeIndex);
    }

    // 移除字节序设置，使用系统默认
    ui->comboByteOrder->setCurrentText(byteOrderToString(QSysInfo::ByteOrder));
}
// 更新音频显示信息
// 参数: blockSize - 数据块大小
// 功能: 更新UI上显示的数据块大小和缓冲区大小信息
void MainWindow::updateAudioDisplay(qint64 blockSize)
{
    // 更新数据块大小
    ui->LabBlockSize->setText(
        QString("IODevice数据块字节数=%1").arg(blockSize));

    // 更新缓冲区大小
    if(audioInput) {
        ui->LabBufferSize->setText(
            QString("QAudioInput::bufferSize()=%1").arg(audioInput->bufferSize()));
    }
}
// 更新音频配置
// 功能: 根据当前UI设置重新配置音频输入参数
void MainWindow::updateAudioConfig()
{
    // 只有在音频运行时才需要重新配置
    if (!isRunning || !audioInput || !displayDevice) return;

    // 停止当前的音频输入
    audioInput->stop();
    displayDevice->close();

    // 更新音频格式
    format.setSampleRate(ui->comboSampleRate->currentText().toInt());
    format.setChannelCount(ui->comboChannels->currentText().toInt());
    format.setSampleFormat(static_cast<QAudioFormat::SampleFormat>(
        ui->comboSampleTypes->currentData().toInt()));

    // 检查格式是否被支持
    if (!curDevice.isFormatSupported(format)) {
        // 如果不支持，使用设备的首选格式
        QAudioFormat preferredFormat = curDevice.preferredFormat();
        // 更新UI以显示实际使用的格式
        ui->comboSampleRate->setCurrentText(QString::number(preferredFormat.sampleRate()));
        ui->comboChannels->setCurrentText(QString::number(preferredFormat.channelCount()));
        
        int sampleTypeIndex = ui->comboSampleTypes->findData(preferredFormat.sampleFormat());
        if(sampleTypeIndex >= 0) {
            ui->comboSampleTypes->setCurrentIndex(sampleTypeIndex);
        }
        
        // 更新format为首选格式
        format = preferredFormat;
    }

    // 设置音频模式
    if (ui->radioPCM->isChecked()) {
        displayDevice->setAudioMode(QmyDisplayDevice::PCM);
    } else {
        displayDevice->setAudioMode(QmyDisplayDevice::ATUIM);
    }

    // 重新创建音频输入
    audioInput = std::make_unique<QAudioSource>(curDevice, format, this);
    
    // 重新打开显示设备并开始
    displayDevice->open(QIODevice::WriteOnly);
    audioInput->start(displayDevice.get());
}

// 开始录音动作触发槽函数
// 功能: 初始化音频输入，创建显示设备，开始录音和计时
void MainWindow::on_actStart_triggered()
{
    // 清空之前的录音数据
    audioBuffer.clear();
    
    // 设置音频格式（Qt6方式）
    format.setSampleRate(ui->comboSampleRate->currentText().toInt());
    format.setChannelCount(ui->comboChannels->currentText().toInt());
    format.setSampleFormat(static_cast<QAudioFormat::SampleFormat>(
        ui->comboSampleTypes->currentData().toInt()));

    // 创建音频输入
    audioInput = std::make_unique<QAudioSource>(curDevice, format, this);

    // 创建显示设备
    displayDevice = std::make_unique<QmyDisplayDevice>(lineSeries, barSeries, barSet, displayPointsCount, this);
    
    // 先连接信号
    connect(displayDevice.get(), &QmyDisplayDevice::updateBlockSize, this, &MainWindow::updateBlockSizeDisplay);
    // 连接音频数据可用信号
    connect(displayDevice.get(), &QmyDisplayDevice::audioDataAvailable, this, [this](const QByteArray &data) {
        audioBuffer.append(data);
    });
    
    // 再打开设备
    displayDevice->open(QIODevice::WriteOnly);

    // 开始录音
    audioInput->start(displayDevice.get());
    isRunning = true;

    // 开始计时
    startTime = QDateTime::currentDateTime();
    elapsedTimer.start();
    recordingTimer->start();
    
    // 更新UI显示开始时间
    ui->begin->setText("开始录音时间: " + startTime.toString("yyyy-MM-dd HH:mm:ss"));
    ui->progressBar->setValue(0);

    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);
}

// 停止录音动作触发槽函数
// 功能: 停止音频输入，关闭显示设备，停止计时
void MainWindow::on_actStop_triggered()
{
    if(audioInput) {
        audioInput->stop();
        audioInput.reset();
    }

    if(displayDevice) {
        displayDevice->close();
        displayDevice.reset();
    }

    // 停止计时
    recordingTimer->stop();
    
    isRunning = false;

    ui->actStart->setEnabled(true);
    ui->actStop->setEnabled(false);
}

// 更新录音时间显示
// 功能: 定期更新录音时长和进度条显示
void MainWindow::updateRecordingTime()
{
    // 计算录音时长
    qint64 elapsedTime = elapsedTimer.elapsed(); // 毫秒
    int seconds = elapsedTime / 1000;
    
    // 更新进度条
    ui->progressBar->setValue(seconds);
    ui->progressBar->setFormat(QString("%1秒").arg(seconds));
}

// 保存文件动作触发槽函数
// 功能: 将录音数据保存为WAV格式文件
void MainWindow::on_actSaveFile_triggered()
{
    if (audioBuffer.isEmpty()) {
        QMessageBox::warning(this, "警告", "没有录音数据可保存！");
        return;
    }

    // 简单的保存功能，使用固定文件名
    const char* fileName = "audio_recording.wav";

    // 使用标准C文件操作
    FILE* file = fopen(fileName, "wb");
    if (!file) {
        QMessageBox::critical(this, "错误", "无法打开文件进行写入！");
        return;
    }

    // 写入WAV文件头
    // RIFF Header
    fwrite("RIFF", 1, 4, file);
    quint32 fileSize = 36 + audioBuffer.size();
    fwrite(&fileSize, 1, 4, file);
    fwrite("WAVE", 1, 4, file);
    
    // fmt subchunk
    fwrite("fmt ", 1, 4, file);
    quint32 fmtSize = 16;
    fwrite(&fmtSize, 1, 4, file);
    
    // 音频格式：1 = PCM
    quint16 audioFormat = 1;
    fwrite(&audioFormat, 1, 2, file);
    
    // 声道数
    quint16 numChannels = format.channelCount();
    fwrite(&numChannels, 1, 2, file);
    
    // 采样率
    quint32 sampleRate = format.sampleRate();
    fwrite(&sampleRate, 1, 4, file);
    
    // 字节率
    quint16 bytesPerSample = 0;
    switch (format.sampleFormat()) {
        case QAudioFormat::UInt8: bytesPerSample = 1;
            break;
        case QAudioFormat::Int16: bytesPerSample = 2;
            break;
        case QAudioFormat::Int32: 
        case QAudioFormat::Float: bytesPerSample = 4;
            break;
        default: bytesPerSample = 2;
    }
    quint32 byteRate = sampleRate * numChannels * bytesPerSample;
    fwrite(&byteRate, 1, 4, file);
    
    // 块对齐
    quint16 blockAlign = numChannels * bytesPerSample;
    fwrite(&blockAlign, 1, 2, file);
    
    // 每样本位数
    quint16 bitsPerSample = bytesPerSample * 8;
    fwrite(&bitsPerSample, 1, 2, file);
    
    // data subchunk
    fwrite("data", 1, 4, file);
    quint32 dataSize = audioBuffer.size();
    fwrite(&dataSize, 1, 4, file);
    
    // 写入音频数据
    fwrite(audioBuffer.constData(), 1, audioBuffer.size(), file);
    fclose(file);

    QMessageBox::information(this, "成功", "录音文件已成功保存为：audio_recording.wav");
}



// 采样率变化槽函数
// 参数: 选中的索引(未使用)
// 功能: 当采样率变化时更新音频配置
void MainWindow::on_comboSampleRate_currentIndexChanged(int)
{
    updateAudioConfig();
}

// 声道数变化槽函数
// 参数: 选中的索引(未使用)
// 功能: 当声道数变化时更新音频配置
void MainWindow::on_comboChannels_currentIndexChanged(int)
{
    updateAudioConfig();
}

// 采样类型变化槽函数
// 参数: 选中的索引(未使用)
// 功能: 当采样类型变化时更新音频配置
void MainWindow::on_comboSampleTypes_currentIndexChanged(int)
{
    updateAudioConfig();
}

// PCM模式切换槽函数
// 参数: checked - 是否选中PCM模式
// 功能: 切换到PCM音频处理模式
void MainWindow::on_radioPCM_toggled(bool checked)
{
    if (checked) {
        // PCM模式：使用正常的音频处理
        if (isRunning && displayDevice) {
            displayDevice->setAudioMode(QmyDisplayDevice::PCM);
            // 重新配置音频以应用新模式
            updateAudioConfig();
        }
    }
}

// ATUIM模式切换槽函数
// 参数: checked - 是否选中ATUIM模式
// 功能: 切换到ATUIM音频处理模式
void MainWindow::on_radioATUIM_toggled(bool checked)
{
    if (checked) {
        // ATUIM模式：使用特殊的音频处理
        if (isRunning && displayDevice) {
            displayDevice->setAudioMode(QmyDisplayDevice::ATUIM);
            // 重新配置音频以应用新模式
            updateAudioConfig();
        }
    }
}

// 设备测试动作触发槽函数
// 功能: 测试当前选择的音频格式是否被设备支持
void MainWindow::on_actDeviceTest_triggered()
{
    QAudioFormat testFormat;
    testFormat.setSampleRate(ui->comboSampleRate->currentText().toInt());
    testFormat.setChannelCount(ui->comboChannels->currentText().toInt());
    testFormat.setSampleFormat(static_cast<QAudioFormat::SampleFormat>(
        ui->comboSampleTypes->currentData().toInt()));

    if(curDevice.isFormatSupported(testFormat)) {
        QMessageBox::information(this, "测试", "设备支持当前格式");
    } else {
        QMessageBox::warning(this, "测试", "设备不支持当前格式");
    }
}

// 更新数据块大小显示
// 参数: blockSize - 数据块大小
// 功能: 更新UI上显示的数据块大小信息
void MainWindow::updateBlockSizeDisplay(qint64 blockSize)
{
    ui->LabBlockSize->setText(QString("数据块大小: %1 字节").arg(blockSize));

    if(audioInput) {
        ui->LabBufferSize->setText(
            QString("缓冲区大小: %1").arg(audioInput->bufferSize()));
    }
}

// 线形图切换槽函数
// 参数: checked - 是否选中线形图
// 功能: 切换到线形图显示模式
void MainWindow::on_radioLineChart_toggled(bool checked)
{
    if (checked) {
        switchChartType(LineChart);
    }
}

// 矩形图切换槽函数
// 参数: checked - 是否选中矩形图
// 功能: 切换到矩形图显示模式
void MainWindow::on_radioRectChart_toggled(bool checked)
{
    if (checked) {
        switchChartType(RectChart);
    }
}

// 切换图表类型的辅助函数
// 参数: type - 要切换的图表类型
// 功能: 通过显示/隐藏不同的图表视图来切换图表类型
void MainWindow::switchChartType(ChartType type)
{
    if (currentChartType == type) return;
    
    // 简单地显示/隐藏不同的图表视图
    if (type == LineChart) {
        ui->chartView->show();
        rectChartView->hide();
    } else {
        ui->chartView->hide();
        rectChartView->show();
    }
    
    currentChartType = type;
    
    // 图表切换不需要重置数据，因为两个图表同时在接收数据更新
    // 不再需要通知displayDevice图表类型变化，因为它始终同时更新两种图表
}

// MainWindow析构函数
// 功能: 释放UI资源
MainWindow::~MainWindow()
{
    delete ui;
}
